#include <iostream>
#include <string>
#include <list>
#include <memory>

using std::cout;
using std::endl;
using std::string;
using std::list;
using std::unique_ptr;

class Observer {
public:
    virtual void update(int x) = 0;

    virtual ~Observer() {}
};

class ConcreteObserver1 : public Observer {
public:
    ConcreteObserver1(const string &name) : _name(name) {
    }

    virtual void update(int x) override {
        cout << ">>ConcreteObserver1  name " << _name
             << ", value " << x << endl;
    }

private:
    string _name;
};

class ConcreteObserver2 : public Observer {
public:
    ConcreteObserver2(const string &name)
            : _name(name) {

    }

    virtual void update(int x) override {
        cout << ">>ConcreteObserver2  name " << _name
             << ", value " << x << endl;
    }

private:
    string _name;
};

class Subject {
public:
    //添加观察者
    virtual void attach(Observer *pobserver) = 0;

    //移除观察者
    virtual void detach(Observer *pobserver) = 0;

    //发通知
    virtual void notify() = 0;

    virtual ~Subject() {}
};

class ConcreteSubject : public Subject {
public:
    virtual void attach(Observer *pobserver) override {
        if (pobserver) {
            _obtList.push_back(pobserver);
        }
    }

    //移除观察者
    virtual void detach(Observer *pobserver) override {
        if (pobserver) {
            _obtList.remove(pobserver);
        }
    }

    //发通知
    virtual void notify() override {
        for (auto &ob: _obtList) {
            ob->update(_status);//体现多态
        }
    }

    void setStatus(int status) {
        _status = status;
    }

    int getStatus() {
        return _status;
    }

    ~ConcreteSubject() {}

private:
    list<Observer *> _obtList;
    int _status;
};

void test() {
    unique_ptr<Observer> po1(new ConcreteObserver1("xiaohong"));
    unique_ptr<Observer> po2(new ConcreteObserver2("wangdao"));
    unique_ptr<ConcreteSubject> psub(new ConcreteSubject());

    //将两个观察者添加到主题中
    psub->attach(po1.get());
    psub->attach(po2.get());
    //当主题的状态发生改变之后，所有观察者的状态都会更新
    psub->setStatus(10);
    psub->notify();

    //某个观察者不想观察主题
    cout << endl << endl;
    psub->detach(po2.get());
    //当主题的状态再次发生变更之后，观察者2的状态就不会更新
    //（收不到通知）
    psub->setStatus(20);
    psub->notify();
}

int main(int argc, char *argv[]) {
    test();
    return 0;
}

